{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 函数式编程\n",
    "函数式编程时Python里面很有意思的一个特性，可以让我们的代码更加简洁和优美。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<map object at 0x000002252744BEB8>\n",
      "[1.0, 1.4142135623730951, 1.7320508075688772, 2.0, 2.23606797749979]\n",
      "[1.0, 1.4142135623730951, 1.7320508075688772, 2.0, 2.23606797749979]\n"
     ]
    }
   ],
   "source": [
    "#map映射\n",
    "#求[1,2,3,4,5]中，每个数字的平方根\n",
    "from math import sqrt\n",
    "nums = [1,2,3,4,5]\n",
    "result = map(sqrt,nums)\n",
    "print(result)\n",
    "print(list(result))\n",
    "#也可以写成如下形式\n",
    "print([sqrt(x) for x in nums])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'xh': 1, 'zongping': 93}, {'xh': 2, 'zongping': 83}, {'xh': 3, 'zongping': 73}, {'xh': 4, 'zongping': 63}, {'xh': 5, 'zongping': 53}, {'xh': 6, 'zongping': 43}]\n",
      "[{'xh': 1, 'zongping': 93}, {'xh': 2, 'zongping': 83}, {'xh': 3, 'zongping': 73}, {'xh': 4, 'zongping': 63}, {'xh': 5, 'zongping': 53}, {'xh': 6, 'zongping': 43}]\n"
     ]
    }
   ],
   "source": [
    "#map映射\n",
    "scores=[\n",
    "    {'xh':1,'qimo':88,'pingshi':99,'queke':16},\n",
    "    {'xh':2,'qimo':78,'pingshi':89,'queke':12},\n",
    "    {'xh':3,'qimo':68,'pingshi':79,'queke':8},\n",
    "    {'xh':4,'qimo':58,'pingshi':69,'queke':4},\n",
    "    {'xh':5,'qimo':48,'pingshi':59,'queke':0},\n",
    "    {'xh':6,'qimo':38,'pingshi':49,'queke':0}\n",
    "]\n",
    "\n",
    "def zongpin(score):\n",
    "    newscore={}\n",
    "    newscore['xh'] = score['xh']\n",
    "    newscore['zongping'] = (score['qimo'] + score['pingshi'])//2\n",
    "    return newscore\n",
    "print(list(map(zongpin,scores)))\n",
    "#也可以写成如下形式\n",
    "print([zongpin(x) for x in scores])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2, 4]\n",
      "[2, 4]\n"
     ]
    }
   ],
   "source": [
    "#filter过滤\n",
    "#是否偶数\n",
    "def iseven(value):\n",
    "    return value%2==0\n",
    "\n",
    "nums = [1,2,3,4,5]\n",
    "result = filter(iseven,nums)\n",
    "print(list(result))\n",
    "#也可以写成如下形式\n",
    "print([x for x in nums if iseven(x)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'xh': 4, 'qimo': 58, 'pingshi': 69, 'queke': 4}, {'xh': 5, 'qimo': 48, 'pingshi': 59, 'queke': 0}, {'xh': 6, 'qimo': 38, 'pingshi': 49, 'queke': 0}]\n",
      "[{'xh': 4, 'qimo': 58, 'pingshi': 69, 'queke': 4}, {'xh': 5, 'qimo': 48, 'pingshi': 59, 'queke': 0}, {'xh': 6, 'qimo': 38, 'pingshi': 49, 'queke': 0}]\n"
     ]
    }
   ],
   "source": [
    "#filter过滤\n",
    "#旷课<15次，成绩有效\n",
    "def isvalid(score):\n",
    "    return score['queke']<8\n",
    "\n",
    "print(list(filter(isvalid,scores)))\n",
    "#也可以写成如下形式\n",
    "print([x for x in scores if isvalid(x)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<function <lambda> at 0x00000225274369D8>\n",
      "25\n",
      "<function <lambda> at 0x0000022527436D08>\n",
      "25\n"
     ]
    }
   ],
   "source": [
    "#lambda表达式\n",
    "#lambda表达式在很多时候可以简化编程，本质上该函数是个匿名函数，使用表达式代替函数\n",
    "lambda x:x**2\n",
    "pf = lambda k:k**2\n",
    "print(pf)\n",
    "print(pf(5))\n",
    "print(lambda x:x**2)\n",
    "print((lambda x:x**2)(5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2, 4]\n",
      "[2, 4]\n"
     ]
    }
   ],
   "source": [
    "#上面的map和filter可以用lambada来改造\n",
    "#是否偶数\n",
    "nums = [1,2,3,4,5]\n",
    "result = filter(lambda v:v%2==0,nums)\n",
    "print(list(result))\n",
    "#也可以写成如下形式\n",
    "print([x for x in nums if x%2==0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'xh': 2, 'qimo': 78, 'pingshi': 89, 'queke': 12}, {'xh': 3, 'qimo': 68, 'pingshi': 79, 'queke': 8}, {'xh': 4, 'qimo': 58, 'pingshi': 69, 'queke': 4}, {'xh': 5, 'qimo': 48, 'pingshi': 59, 'queke': 0}, {'xh': 6, 'qimo': 38, 'pingshi': 49, 'queke': 0}]\n",
      "[{'xh': 2, 'qimo': 78, 'pingshi': 89, 'queke': 12}, {'xh': 3, 'qimo': 68, 'pingshi': 79, 'queke': 8}, {'xh': 4, 'qimo': 58, 'pingshi': 69, 'queke': 4}, {'xh': 5, 'qimo': 48, 'pingshi': 59, 'queke': 0}, {'xh': 6, 'qimo': 38, 'pingshi': 49, 'queke': 0}]\n"
     ]
    }
   ],
   "source": [
    "#旷课<15次，成绩有效\n",
    "print(list(filter(lambda score:score['queke']<15,scores)))\n",
    "#也可以写成如下形式\n",
    "print([x for x in scores if x['queke']<15])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#任务\n",
    "#任务5.1 结合map filter 和 lambda来实现求1000以内的质数\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "1\n",
      "2\n"
     ]
    },
    {
     "ename": "StopIteration",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mStopIteration\u001b[0m                             Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-31-b5071dd4775a>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      8\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnext\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mit\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[1;31m#如果遍历完了，会报StopIteration异常\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnext\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mit\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mStopIteration\u001b[0m: "
     ]
    }
   ],
   "source": [
    "#iterator迭代器\n",
    "#迭代器是个对象，提供了统一的方法next(iterator)遍历数据\n",
    "#使用iter(data)可以对可迭代的数据创建迭代器\n",
    "fibs = [1,1,2]\n",
    "it = iter(fibs)\n",
    "print(next(it))\n",
    "print(next(it))\n",
    "print(next(it))\n",
    "#如果遍历完了，会报StopIteration异常\n",
    "print(next(it))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "1\n",
      "2\n",
      "1\n",
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "#我们用for in进行遍历的时候，本质上是使用了迭代器\n",
    "for x in fibs:\n",
    "    print(x)\n",
    "#相当于\n",
    "for x in iter(fibs):\n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 4, 9, 16, 25, 36]\n",
      "<generator object <genexpr> at 0x000002D716D5D408>\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "#generator生成器\n",
    "#我们之前学过列表的增强写法比如\n",
    "score=[1,2,3,4,5,6]\n",
    "score2 = [x*x for x in score]\n",
    "score3 = (x*x for x in score)\n",
    "print(score2)\n",
    "#我们会发现score3，其实就是个生成器，所以score3并不计算和遍历，只有对该生成器进行遍历的时候才会调用\n",
    "#如果数据量很大的时候，每一步都要求解的话，会花费大量的时间。所有generator的优势就体现出来了。\n",
    "#通常可以减少内存的使用\n",
    "print(score3)\n",
    "print(9 in score2)\n",
    "print(9 in score3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<generator object generate_scores at 0x0000022527435C78>\n",
      "<class 'generator'>\n",
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "#生成器返回的是个interator迭代器\n",
    "#在python中可以通过yield得到一个生成器函数\n",
    "def generate_scores():\n",
    "    for s in score:\n",
    "        yield s\n",
    "\n",
    "g = generate_scores()\n",
    "print(g)\n",
    "print(type(g))\n",
    "print(next(g))\n",
    "print(next(g))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 1 2 3 5 8 13 21 34 55 \n",
      "1\n",
      "1\n",
      "2\n",
      "3\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "#生成斐波那契数列\n",
    "def fibonacci(n):\n",
    "    a,b=0,1\n",
    "    for i in range(n):\n",
    "        print(b,end=' ')\n",
    "        a,b = b, a+b\n",
    "    \n",
    "fibonacci(10)\n",
    "print()\n",
    "#通过生成器来\n",
    "def generate_fibs():\n",
    "    a,b = 0,1\n",
    "    while True:\n",
    "        a,b=b,a+b\n",
    "        yield a\n",
    "\n",
    "gfib = generate_fibs()\n",
    "print(next(gfib))\n",
    "print(next(gfib))\n",
    "print(next(gfib))\n",
    "print(next(gfib))\n",
    "print(next(gfib))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#在生成器generate_fibs中，有个while True所以这个迭代器可以无限的迭代下去的，在调用的时候要防止无穷调用的问题\n",
    "#比如通过max调用\n",
    "print(max(gfib))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#任务5.2 准备一个文件5.2.1.txt，随机生成1000个0-1000的数字放在里面\n",
    "#然后求解每个数字的平方放5.2.2.txt\n",
    "#最后输出总和"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "包装函数f\n",
      "2020-04-02 07:22:20.961269开始调用f(3,4)\n",
      "2020-04-02 07:22:20.961269调用结束,结果是25\n",
      "2020-04-02 07:22:20.961269开始调用f(4)\n",
      "2020-04-02 07:22:20.961269调用结束,结果是16\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "16"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import datetime\n",
    "#装饰器\n",
    "#装饰器就类似于java中的注解，作用是再不修改函数代码的基础上改变函数的行为，\n",
    "#可以用来在函数被被调用前后做出一些处理\n",
    "#如果要实现装饰器行为，首先函数要能作为参数传递，还可以作为返回值返回，\n",
    "#只有这样装饰器就可以装饰普通函数，是你感觉得到了一个新的函数\n",
    "#下面我们来定义一个函数 f(x,y,z...) = x*x+y*y+z*z...\n",
    "def f(*args):\n",
    "    return sum([x*x for x in args])\n",
    "#然后我们定义一个函数logger,可以接收函数f，返回新的函数\n",
    "def logger(function):\n",
    "    print(\"包装函数{}\".format(function.__name__))\n",
    "    def wrapper(*args,**kwargs):\n",
    "        \n",
    "        print(\"{}开始调用{}({})\".format(datetime.datetime.utcnow(),function.__name__,(','.join([str(x) for x in args]))))\n",
    "        result = function(*args,**kwargs)\n",
    "        print(\"{}调用结束,结果是{}\".format(datetime.datetime.utcnow(),result))\n",
    "        return result\n",
    "    return wrapper\n",
    "#这一步作用是包装函数f(x)返回新的函数\n",
    "newfunc = logger(f)\n",
    "#调用\n",
    "newfunc(3,4)\n",
    "#调用\n",
    "newfunc(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "包装函数pingfanghe\n",
      "2020-04-02 07:22:28.933905开始调用pingfanghe(1,2,3)\n",
      "2020-04-02 07:22:28.933905调用结束,结果是14\n",
      "2020-04-02 07:22:28.933905开始调用pingfanghe(4,5,6)\n",
      "2020-04-02 07:22:28.933905调用结束,结果是77\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "77"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#我们可以使用装饰器的语法来实现上述功能\n",
    "#程序结构变得更加清晰\n",
    "@logger\n",
    "def pingfanghe(*args):\n",
    "    return sum([x*x for x in args])\n",
    "\n",
    "pingfanghe(1,2,3)\n",
    "pingfanghe(4,5,6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#任务5.3 编写装饰器mylog 把函数的调用记录到5.3.log文件中，并记录时间"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
